#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
数据处理模块
负责读取和处理调度相关数据
"""

import numpy as np 
import pandas as pd
from typing import Dict, List, Tuple, Any
import os
import warnings

warnings.filterwarnings("ignore", category=FutureWarning)

class DataProcessor:
    """数据处理类，处理订单和机器相关数据"""
    
    def __init__(self, order_num: int = 0, machine_num: int = 0):
        """初始化数据处理对象
        
        Args:
            order_num: 订单数量
            machine_num: 机器数量
        """
        self.order_num = order_num
        self.machine_num = machine_num
        
    def get_order_machine_count(self) -> Tuple[int, int]:
        """获取订单数和机器数
        
        Returns:
            订单数和机器数的元组
        """
        return self.order_num, self.machine_num
    
    def read(self, data: pd.DataFrame) -> Tuple[Dict, List, np.ndarray]:
        """处理数据框中的订单和机器信息
        
        Args:
            data: 包含订单和机器信息的DataFrame
            
        Returns:
            处理后的信息字典、交付时间列表和工作数组
        """
        delivery_time = []
        info = dict()
        work = []
        
        for i in range(self.order_num):
            info[i] = dict()
            jobdf = data[data['order'] == (i+1)]
            delivery_time.append(jobdf.iloc[0, -1])
            jobdf = jobdf.iloc[:, 2:-1]
            
            for j in range(jobdf.shape[0]):
                work.append(i)
                info[i][j] = dict()
                
                for k in range(0, self.machine_num):
                    machine_time = jobdf.iloc[j, k]
                    if machine_time != '-':
                        info[i][j][k+1] = machine_time
                        
        work = np.array(work)
        return info, delivery_time, work

    def read_first(self, filename: str) -> Tuple[Dict, List, np.ndarray]:
        """读取上次普通调度的数据
        
        Args:
            filename: 数据文件名
            
        Returns:
            处理后的信息字典、交付时间列表和工作数组
        """
        data = pd.read_excel(filename, skiprows=1)
        data = data.ffill()
        self.order_num = len(data.iloc[:, 0].unique())
        self.machine_num = len(data.columns) - 3
        
        # 保持原始字符串不变
        data.columns = ['order', 'procedure'] + ['M'+str(i) for i in range(1, self.machine_num+1)] + ['delivery_time']
        
        info, delivery_time, work = self.read(data)
        return info, delivery_time, work

    def read_Rescheduling(self, machine_file: str, first_scheduling_result: str, insert_order_file: str) -> Tuple:
        """
        读取重调度相关文件
        
        Args:
            machine_file: 机器信息文件
            first_scheduling_result: 第一次调度结果文件
            insert_order_file: 插入订单文件
            
        Returns:
            处理后的调度数据
        """
        from config.config import FIRST_SCHEDULING_RESULT_PATH

        # 1. 读取第一次调度结果
        data = pd.read_excel(FIRST_SCHEDULING_RESULT_PATH)
        data['工序完成时间'] = data['工序开始时间'] + data['工序加工时间']
        
        # 2. 读取插入订单信息
        insertdf = pd.read_excel(insert_order_file, skiprows=1)
        insertdf.columns = list(insertdf.columns[:-2]) + ['插入时间', '交货时间']
        insertdf = insertdf.ffill()
        insertpoint = insertdf.iloc[0, -2]
        
        # 3. 确定插入点时正在加工的作业
        eing = data[(data['工序开始时间'] <= insertpoint) & (data['工序完成时间'] > insertpoint)].reset_index(drop=True)
        eing['剩余加工时间'] = eing['工序完成时间'] - insertpoint
        jobing = np.array(eing[['订单编号', '机器编号', '剩余加工时间']])
        
        # 4. 区分已完成和未完成的作业
        nojob = data[(data['工序开始时间'] <= insertpoint)].reset_index(drop=True)
        rejob = data[(data['工序开始时间'] > insertpoint)].reset_index(drop=True)
        
        # 5. 读取机器信息
        machineinfo = pd.read_excel(machine_file, skiprows=1)
        machineinfo.columns = list(machineinfo.columns)[:-1] + ['交货时间']
        machineinfo = machineinfo.ffill()
        
        # 6. 整合未完成作业和机器信息
        rejobmachine = pd.DataFrame(columns=machineinfo.columns)
        for i in rejob.index:
            matching_rows = machineinfo[
                (machineinfo['订单'] == rejob.loc[i, '订单编号']) & 
                (machineinfo['工序'] == rejob.loc[i, '订单的工序号'])
            ]
            if not matching_rows.empty:
                rejobmachine = pd.concat([rejobmachine, matching_rows])
                
        rejobmachine = pd.concat([rejobmachine, insertdf.drop('插入时间', axis=1)]).reset_index(drop=True)
        
        # 7. 更新订单和机器数量
        self.order_num = len(rejobmachine['订单'].unique())
        self.machine_num = len(rejobmachine.columns) - 3
        
        # 8. 创建作业字典
        jobdic = dict()
        neworder = 1
        orderlis = rejobmachine['订单'].unique()
        
        for r in orderlis:
            jobdf = rejobmachine[rejobmachine['订单'] == r]
            jobdic[neworder] = (r, jobdf['工序'].min())
            rejobmachine['订单'] = rejobmachine['订单'].replace(r, neworder)
            neworder = neworder + 1

            
        # 保持原始字符串不变
        rejobmachine.columns = ['order', 'procedure'] + ['M'+str(i) for i in range(1, self.machine_num+1)] + ['delivery_time']
        
        # 按照先订单后工序排序
        rejobmachine = rejobmachine.sort_values(by=['order', 'procedure']).reset_index(drop=True)
        
        # 同样按照先订单后工序排序nojob
        nojob = nojob.sort_values(by=['订单编号', '订单的工序号']).reset_index(drop=True)
        
        # 添加以下代码：保存rejobmachine到Excel文件
        try:
            # 获取项目根目录
            project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
            
            # 创建实验目录（如果不存在）
            from src.utils import get_experiment_dir
            exp_dir = get_experiment_dir()
            
            # 保存rejobmachine到实验目录
            rejob_path = os.path.join(exp_dir, 'rejobmachine.xlsx')
            rejobmachine.to_excel(rejob_path, index=False)

            # 同时保存一份到项目根目录
            fixed_rejob_path = os.path.join(project_root, 'rejobmachine.xlsx')
            rejobmachine.to_excel(fixed_rejob_path, index=False)

            # ---------------------------------------------------------------------------------------------------------

            nojob_path=os.path.join(exp_dir, 'nojob.xlsx')
            nojob.to_excel(nojob_path, index=False)

            # 同时保存一份到项目根目录
            fixed_nojob_path = os.path.join(project_root, 'nojob.xlsx')
            nojob.to_excel(fixed_nojob_path, index=False)
            
            print(f"rejobmachine数据已保存至: {rejob_path}")
            print(f"rejobmachine数据已额外保存至: {fixed_rejob_path}")
        except Exception as e:
            print(f"保存rejobmachine数据时出错: {e}")

        reinfo, delivery_time, work = self.read(rejobmachine)
        return reinfo, delivery_time, work, jobdic, jobing, insertpoint, nojob

    def read_MaintenanceRescheduling(self, machine_file: str, first_scheduling_result: str) -> Tuple:
        """
        读取重调度相关文件

        Args:
            machine_file: 机器信息文件
            first_scheduling_result: 第一次调度结果文件
            insert_order_file: 插入订单文件

        Returns:
            处理后的调度数据
        """
        from config.config import FIRST_SCHEDULING_RESULT_PATH, MAINTENANCE_TIME, MAINTENANCE_MACHINE, MAINTENANCE_DURATION

        # 1. 读取第一次调度结果
        data = pd.read_excel(FIRST_SCHEDULING_RESULT_PATH)
        data['工序完成时间'] = data['工序开始时间'] + data['工序加工时间']

        # # 2. 读取插入订单信息
        # insertdf = pd.read_excel(insert_order_file, skiprows=1)
        # insertdf.columns = list(insertdf.columns[:-2]) + ['插入时间', '交货时间']
        # insertdf = insertdf.ffill()
        # insertpoint = insertdf.iloc[0, -2]

        # 3. 确定插入点时正在加工的作业
        eing = data[(data['工序开始时间'] <= MAINTENANCE_TIME) & (data['工序完成时间'] > MAINTENANCE_TIME)].reset_index(drop=True)
        eing['剩余加工时间'] = eing['工序完成时间'] - MAINTENANCE_TIME
        # jobing = np.array(eing[['订单编号', '机器编号', '剩余加工时间']])

        # 从eing中提取需要的列
        jobing_data = eing[['订单编号', '机器编号', '剩余加工时间']]

        # 创建维护作业并确保列名一致

        maintenance = pd.DataFrame([[-1, MAINTENANCE_MACHINE, MAINTENANCE_DURATION]],
                                   columns=['订单编号', '机器编号', '剩余加工时间'])

        # 连接两个DataFrame并重置索引
        jobing_combined = pd.concat([jobing_data, maintenance], ignore_index=True)

        # 转换为numpy数组以便后续处理
        jobing = jobing_combined.values

        # 4. 区分已完成和未完成的作业
        nojob = data[(data['工序开始时间'] <= MAINTENANCE_TIME)].reset_index(drop=True)
        rejob = data[(data['工序开始时间'] > MAINTENANCE_TIME)].reset_index(drop=True)

        # 5. 读取机器信息
        machineinfo = pd.read_excel(machine_file, skiprows=1)
        machineinfo.columns = list(machineinfo.columns)[:-1] + ['交货时间']
        machineinfo = machineinfo.ffill()

        # 6. 整合未完成作业和机器信息
        rejobmachine = pd.DataFrame(columns=machineinfo.columns)
        for i in rejob.index:
            matching_rows = machineinfo[
                (machineinfo['订单'] == rejob.loc[i, '订单编号']) &
                (machineinfo['工序'] == rejob.loc[i, '订单的工序号'])
                ]
            if not matching_rows.empty:
                rejobmachine = pd.concat([rejobmachine, matching_rows])

        rejobmachine = rejobmachine.sort_values(by='订单').reset_index(drop=True)
        # rejobmachine = pd.concat([rejobmachine, insertdf.drop('插入时间', axis=1)]).reset_index(drop=True)

        # 7. 更新订单和机器数量
        self.order_num = len(rejobmachine['订单'].unique())
        self.machine_num = len(rejobmachine.columns) - 3

        # 8. 创建作业字典
        jobdic = dict()
        neworder = 1
        orderlis = rejobmachine['订单'].unique()

        for r in orderlis:
            jobdf = rejobmachine[rejobmachine['订单'] == r]
            jobdic[neworder] = (r, jobdf['工序'].min())
            rejobmachine['订单'] = rejobmachine['订单'].replace(r, neworder)
            neworder = neworder + 1

        # 保持原始字符串不变
        rejobmachine.columns = ['order', 'procedure'] + ['M' + str(i) for i in range(1, self.machine_num + 1)] + [
            'delivery_time']

        # 按照先订单后工序排序
        rejobmachine = rejobmachine.sort_values(by=['order', 'procedure']).reset_index(drop=True)
        
        # 同样按照先订单后工序排序nojob
        nojob = nojob.sort_values(by=['订单编号', '订单的工序号']).reset_index(drop=True)
        
        # 添加以下代码：保存rejobmachine到Excel文件
        try:
            # 获取项目根目录
            project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
            
            # 创建实验目录（如果不存在）
            from src.utils import get_experiment_dir
            exp_dir = get_experiment_dir()
            
            # 保存rejobmachine到实验目录
            rejob_path = os.path.join(exp_dir, 'rejobmachine.xlsx')
            rejobmachine.to_excel(rejob_path, index=False)

            # 同时保存一份到项目根目录
            fixed_rejob_path = os.path.join(project_root, 'rejobmachine.xlsx')
            rejobmachine.to_excel(fixed_rejob_path, index=False)

            # 保存nojob到实验目录和项目根目录

            nojob_path=os.path.join(exp_dir, 'nojob.xlsx')
            nojob.to_excel(nojob_path, index=False)

            fixed_nojob_path = os.path.join(project_root, 'nojob.xlsx')
            nojob.to_excel(fixed_nojob_path, index=False)

            
            print(f"rejobmachine数据已保存至: {rejob_path}")
            print(f"rejobmachine数据已额外保存至: {fixed_rejob_path}")
        except Exception as e:
            print(f"保存rejobmachine数据时出错: {e}")

        reinfo, delivery_time, work = self.read(rejobmachine)
        return reinfo, delivery_time, work, jobdic, jobing, MAINTENANCE_TIME, nojob